package com.navinfo.platform.etl.flink.protocol.service;

import com.navinfo.platform.etl.enums.Protocol;
import com.navinfo.platform.etl.enums.Yard;
import com.navinfo.platform.etl.flink.protocol.annotation.RoutingProtocol;
import com.navinfo.platform.etl.util.ClassUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.*;

public class InstanceUtils {
    private static final Logger logger = LoggerFactory.getLogger(InstanceUtils.class);
    private static final Map<String, IProtocolParseService> protocolParseServiceMap;
//    private static final Properties prop;
    static {
        protocolParseServiceMap = new HashMap<>();
//        prop = new Properties();
//        try {
//            prop.load(AbstractProtocolSerializer.class.getClass().getResourceAsStream("/config.properties"));
//            System.out.println(prop);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
        scanServiceInstance();
    }

    public static IProtocolParseService getInstanceService(String yardName, String protocol){
//        String yardName = String.valueOf(prop.get("yard.name"));
        int protocolType = Protocol.valueOf(protocol).getProtoType();
        IProtocolParseService service = protocolParseServiceMap.get(yardName + protocolType);
        if(service == null){
            service = protocolParseServiceMap.get(Yard.COMMON.getYardName() + protocolType);
        }
        return service;
    }


    private static void scanServiceInstance(){
        logger.error("scan protocol service, load instance into protocolParseServiceMap, time is " + new Date().toString());
        List<Class<?>> list = ClassUtils.getClasses("com.navinfo.opentsp.platform.computing.service");
        for(Class<?> clazz : list){
            if(IProtocolParseService.class.isAssignableFrom(clazz) && IProtocolParseService.class != clazz){
                final RoutingProtocol routingProtocol = clazz.getAnnotation(RoutingProtocol.class);
                if(routingProtocol != null){
                    protocolParseServiceMap.put(routingProtocol.yard().getYardName() + routingProtocol.protocolType().getProtoType(), getInstance(clazz));
                }else if(!Modifier.isAbstract(clazz.getModifiers())){//ignore AbstractClass
                    //abstract class ignore
                }
            }
        }
    }

    private static <T> T getInstance(Class<?> clazz){
        try {
            Constructor<?> c = clazz.getDeclaredConstructor();
            if (!c.isAccessible()) {
                c.setAccessible(true);
            }
            return (T)c.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
